package com.berchen.等待唤醒机制;

/**
 * 生产者和消费者案例
 * 没有用等待唤醒机制的问题：
 *  生产者已经生成满了，但是还在生产。
 *  消费者已经买完了，但是还在买。没有停止。
     *  生产者进货:0
     *  产品已满，不能添加
     *  消费者卖货+10
     *  缺货
 *
 *  所以我们需要等待唤醒机制解决问题：
 *
 * wait 方法可能会有虚假唤醒的问题，所以通常将wait方法放在循环中。
 */
public class TestProductorAndConsumer {

    public static void main(String[] args){

        Clerk clerk=new Clerk();    // 店员
        Productor productor=new Productor(clerk);
        Consumer consumer=new Consumer(clerk);

        new Thread(productor,"生产者").start();
        new Thread(consumer,"消费者").start();
        new Thread(productor,"生产者1").start();
        new Thread(consumer,"消费者1").start();
    }
}

// 店员
class Clerk{

    private int product=0;  // 共享数据

    // 进货方法
    public synchronized void get(){

        while(product>=10){
            System.out.println("产品已满，不能添加");
            try {
                this.wait();    // 停止生产
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName()+"进货:"+ ++product);
        this.notifyAll();   // 开始生产

    }
    // 卖货方法
    public synchronized void sale(){    // 必须使用锁的对象调用wait方法和notify

        while(product<=0){

            System.out.println("缺货");
            try {
                this.wait();    // 停止卖货
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName()+"卖货 "+product--);
        this.notifyAll();   // 开始卖货

    }
}
// 生产者,生产者可能有多个
class Productor implements Runnable{

    private Clerk clerk;

    public Productor(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {

        for(int i=0;i<20;i++){

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.get();
        }
    }
}

// 消费者
class Consumer implements Runnable{

    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {

        for(int i=0;i<20;i++){
            clerk.sale();
        }
    }
}